// Copyright (c) 2019 Presto Labs Pte. Ltd.
// Author: xguo

#include "coin2/exchange/base/symbology/derivative_util.h"

#include <gtest/gtest.h>

TEST(date_util, example) {
  using namespace coin2::exchange::base::symbology;
  int64_t timestamp;

  ASSERT_TRUE(IsDateStr("20190101"));
  ASSERT_FALSE(IsDateStr("2019101"));    // Invalid format
  ASSERT_FALSE(IsDateStr("20191301"));   // Invalid month
  ASSERT_FALSE(IsDateStr("30190101"));   // Out of normal range
  ASSERT_FALSE(IsDateStr("19690101"));   // Out of normal range
  ASSERT_FALSE(IsDateStr("THIS_WEEK"));  // Not a numeric string

  timestamp = 0;
  EXPECT_EQ(ToDateStr(timestamp), "19700101");

  timestamp = 1572571342 * 1e9;
  EXPECT_EQ(ToDateStr(timestamp), "20191101");

  timestamp = 1577433600 * 1e9;  // 2019-12-27 08:00:00 UTC
  EXPECT_EQ(ToDateStr(timestamp), "20191227");
}

TEST(derivative_util, example) {
  using namespace coin2::exchange::base::symbology;
  int64_t expected_expiry_timestamp;
  int64_t expiry_timestamp;
  int64_t resolve_ts;

  // Friday morning before expiration
  resolve_ts = 1572572068 * 1e9;                 // 2019-11-01 01:34:28 UTC
  expected_expiry_timestamp = 1572595200 * 1e9;  // 2019-11-01 08:00:00 UTC
  expiry_timestamp = FindExpiryFriday(
      ExchangeType::Okex, ContractType::WEEK, resolve_ts, 8 * 3600 * 1e9);
  EXPECT_EQ(expiry_timestamp, expected_expiry_timestamp);

  expected_expiry_timestamp = 1573200000 * 1e9;  // 2019-11-08 08:00:00 UTC
  expiry_timestamp = FindExpiryFriday(
      ExchangeType::Okex, ContractType::NEXT_WEEK, resolve_ts, 8 * 3600 * 1e9);
  EXPECT_EQ(expiry_timestamp, expected_expiry_timestamp);

  expected_expiry_timestamp = 1577433600 * 1e9;  // 2019-12-27 08:00:00 UTC
  expiry_timestamp = FindExpiryFriday(
      ExchangeType::Okex, ContractType::QUARTER, resolve_ts, 8 * 3600 * 1e9);
  EXPECT_EQ(expiry_timestamp, expected_expiry_timestamp);

  // Friday afternoon after expiration
  resolve_ts = (1572572068 + 7 * 3600) * 1e9;                      // 2019-11-01 01:34:28 UTC
  expected_expiry_timestamp = (1572595200 + 7 * 3600 * 24) * 1e9;  // 2019-11-01 08:00:00 UTC
  expiry_timestamp = FindExpiryFriday(
      ExchangeType::Okex, ContractType::WEEK, resolve_ts, 8 * 3600 * 1e9);
  EXPECT_EQ(expiry_timestamp, expected_expiry_timestamp);

  expected_expiry_timestamp = (1573200000 + 7 * 3600 * 24) * 1e9;  // 2019-11-08 08:00:00 UTC
  expiry_timestamp = FindExpiryFriday(
      ExchangeType::Okex, ContractType::NEXT_WEEK, resolve_ts, 8 * 3600 * 1e9);
  EXPECT_EQ(expiry_timestamp, expected_expiry_timestamp);

  expected_expiry_timestamp = 1577433600 * 1e9;  // 2019-12-27 08:00:00 UTC
  expiry_timestamp = FindExpiryFriday(
      ExchangeType::Okex, ContractType::QUARTER, resolve_ts, 8 * 3600 * 1e9);
  EXPECT_EQ(expiry_timestamp, expected_expiry_timestamp);

  // Just 1 second before QUARTER => NEXT_WEEK
  resolve_ts = (1577433600 - 14 * 3600 * 24 - 1) * 1e9;
  expected_expiry_timestamp = 1577433600 * 1e9;  // 2019-12-27 08:00:00 UTC
  expiry_timestamp = FindExpiryFriday(
      ExchangeType::Okex, ContractType::QUARTER, resolve_ts, 8 * 3600 * 1e9);
  EXPECT_EQ(expiry_timestamp, expected_expiry_timestamp);

  // Just 1 second after QUARTER => NEXT_WEEK
  resolve_ts = (1577433600 - 14 * 3600 * 24 + 1) * 1e9;
  int64_t expected_next_week_expiry_timestamp = 1577433600 * 1e9;  // 2019-12-27 08:00:00 UTC
  int64_t expected_quarter_expiry_timestamp = 1585296000 * 1e9;    // 2020-03-27 08:00:00 UTC
  auto next_week_expiry_timestamp =
      FindExpiryFriday(ExchangeType::Okex, ContractType::NEXT_WEEK, resolve_ts, 8 * 3600 * 1e9);
  auto quarter_expiry_timestamp =
      FindExpiryFriday(ExchangeType::Okex, ContractType::QUARTER, resolve_ts, 8 * 3600 * 1e9);
  EXPECT_EQ(next_week_expiry_timestamp, expected_next_week_expiry_timestamp);
  EXPECT_EQ(quarter_expiry_timestamp, expected_quarter_expiry_timestamp);
}
